
type UpdateType = (p: number) => void;
/**
 * 动画类
 * duration 动画时长
 * update   更新函数回调，生成的数值
 * easing    缓动函数
 */
class Animator {
  duration: number;
  update: UpdateType;
  easing: ((p: number) => number) | null;

  constructor(duration: number, update: UpdateType, easing: ((p: number) => number) | null = null) {
    this.duration = duration;
    this.update = update;
    this.easing = easing;
  }

  animate() {
    let startTime = 0;
    const duration = this.duration;
    const update = this.update;
    const easing = this.easing;
    const self = this;

    return new Promise((resolve, reject) => {
      let qId = 0;

      function step(timestamp: number) {
        startTime = startTime || timestamp;
        const p = Math.min(1.0, (timestamp - startTime) / duration);

        update.call(self, easing ? easing(p) : p);

        if (p < 1.0) {
          qId = requestAnimationFrame(step);
        } else {
          resolve(self);
        }
      }

      self.cancel = () => {
        cancelAnimationFrame(qId);
        update.call(self, 0);
        reject("User canceled!");
      };

      qId = requestAnimationFrame(step);
    });
  }

  ease(easing: (p: number) => number) {
    return new Animator(this.duration, this.update, easing);
  }

  cancel?: () => void;
}

export default Animator;

// 示例用法
// let animator = new Animator(2000, function(p) {
//   let tx = -100 * Math.sin(2 * Math.PI * p),
//     ty = -100 * Math.cos(2 * Math.PI * p);

//   block.style.transform = "translate(" + tx + "px," + ty + "px)";
// });
// await animator.animate();